package fatworm.parser.syntree;
/**
 * syntax node
 * represent a select expression 
 */
public class SelectNode extends QueryNode{
	
	public java.util.LinkedList<ValueNode>	selectList = null; 
	public java.util.LinkedList<TableRef> 	fromList 	= null;
	public WhereNode whereCond = null; 
	public java.util.LinkedList<String> groupByList = null;
	public WhereNode havingCond = null;
	public java.util.LinkedList<String> orderByList = null;
	/** the order of the data */
	public fatworm.concept.DataOrder order = null;
	/** whether it's a distinct select */
	public boolean distinct = false;
	/** whether it's a select all select*/
	public boolean selectAll = false;
	
	public SelectNode( java.util.LinkedList<ValueNode> selectList ){
		this.selectList = selectList;
		this.selectAll = false;
	}
	
	/** select all*/
	public SelectNode(){
		this.selectAll = true;
	}
	public void setDistinct(){
		this.distinct = true;
	}
	public boolean isSelectAll(){
		return selectAll;
	}
	public boolean hasFrom(){ 
		return fromList != null;
	}
	public boolean hasWhere(){
		return whereCond != null;
	}
	public boolean hasGroupBy(){
		return groupByList != null;
	}
	public boolean hasHaving(){
		return havingCond != null;
	}
	public boolean hasOrderBy(){
		return orderByList != null;
	}
	
	public String toString(){
		String ans ="SELECT " ;
		if( this.distinct )ans += "DISTINCT ";
		if( this.isSelectAll() ) ans += "* ";
		else{
			for( java.util.Iterator<ValueNode> i = selectList.iterator() ; i.hasNext();)
				ans += i.next() + (i.hasNext() ? ",":"\n\t");
		}
		if( this.hasFrom() ){
			ans += "FROM ";
			for( java.util.Iterator<TableRef> i = fromList.iterator() ; i.hasNext();)
				ans += i.next() + (i.hasNext() ? ",":"\n\t");
		}
		if( this.hasWhere() ){
			ans += "WHERE " + whereCond+"\n\t";	
		}
		if( this.hasGroupBy() ){
			ans += "GROUP BY ";
			for( java.util.Iterator<String> i = groupByList.iterator() ; i.hasNext();)
				ans += i.next() + (i.hasNext() ? ",":"\n\t");
		}
		if( this.hasHaving() ){
			ans += "HAVING " + havingCond+"\n\t";	
		}		
		if( this.hasOrderBy() ){
			ans += "ORDER BY ";
			for( java.util.Iterator<String> i = orderByList.iterator() ; i.hasNext();)
				ans += i.next() + (i.hasNext() ? ",":" "+order);
			
		}			
		return ans;		
	}
	public void accept( IQueryVisitor visitor ){
		visitor.visit( this );
	}
	/** visitor interface to support visitor pattern */
	public interface ITableRefVisitor{
		public void visit( SimpleRef ref );
		public void visit( SubqueryRef ref );
	}
	/** table reference */
	public abstract static class TableRef extends SyntaxNode{ 
		public String alias;
		public TableRef( String alias ){
			this.alias = alias;
		}
		public abstract void accept( ITableRefVisitor visitor );
	}
	/** simple reference to a table in the database */
	public static class SimpleRef extends TableRef{
		public String tableName;
		public SimpleRef( String tableName , String alias ){
			super( alias );
			this.tableName = tableName;
		}
		public SimpleRef( String tableName ){
			this( tableName , tableName );
		}
		public void accept( ITableRefVisitor visitor ){
			visitor.visit( this );
		}
		public String toString(){
			if( tableName.equals( alias )) return tableName;
			else return tableName +" AS "+ alias;
		}
	}
	/** reference to sub query */
	public static class SubqueryRef extends TableRef{
		public SelectNode subquery;
		public SubqueryRef( SelectNode subquery , String alias ){
			super( alias );
			this.subquery = subquery;
		}
		public void accept( ITableRefVisitor visitor ){
			visitor.visit( this );
		}
		public String toString(){
			return "("+subquery+") AS " + alias;
		}
	}
}
